// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie.core.math;

import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Quaternion;
import org.lwjgl.util.vector.Vector3f;
import zombie.debug.DebugLog;
import zombie.iso.Vector2;
import zombie.util.StringUtils;
import zombie.util.list.PZArrayUtil;

public final class PZMath {
    public static final float PI = (float) Math.PI;
    public static final float PI2 = (float) (Math.PI * 2);
    public static final float degToRads = (float) (Math.PI / 180.0);
    public static final float radToDegs = 180.0F / (float)Math.PI;
    public static final long microsToNanos = 1000L;
    public static final long millisToMicros = 1000L;
    public static final long secondsToMillis = 1000L;
    public static long secondsToNanos = 1000000000L;

    public static float almostUnitIdentity(float x) {
        return x * x * (2.0F - x);
    }

    public static float almostIdentity(float x, float m, float n) {
        if (x > m) {
            return x;
        } else {
            float float0 = 2.0F * n - m;
            float float1 = 2.0F * m - 3.0F * n;
            float float2 = x / m;
            return (float0 * float2 + float1) * float2 * float2 + n;
        }
    }

    public static float gain(float x, float k) {
        float _float = (float)(0.5 * Math.pow((double)(2.0F * (x < 0.5F ? x : 1.0F - x)), (double)k));
        return x < 0.5F ? _float : 1.0F - _float;
    }

    public static float clamp(float val, float min, float max) {
        float _float = val;
        if (val < min) {
            _float = min;
        }

        if (_float > max) {
            _float = max;
        }

        return _float;
    }

    public static long clamp(long val, long min, long max) {
        long _long = val;
        if (val < min) {
            _long = min;
        }

        if (_long > max) {
            _long = max;
        }

        return _long;
    }

    public static int clamp(int val, int min, int max) {
        int _int = val;
        if (val < min) {
            _int = min;
        }

        if (_int > max) {
            _int = max;
        }

        return _int;
    }

    public static float clampFloat(float val, float min, float max) {
        return clamp(val, min, max);
    }

    public static float clamp_01(float val) {
        return clamp(val, 0.0F, 1.0F);
    }

    public static float lerp(float src, float dest, float alpha) {
        return src + (dest - src) * alpha;
    }

    public static float lerpAngle(float src, float dest, float alpha) {
        float float0 = getClosestAngle(src, dest);
        float float1 = src + alpha * float0;
        return wrap(float1, (float) -Math.PI, (float) Math.PI);
    }

    public static Vector3f lerp(Vector3f vector3f0, Vector3f vector3f1, Vector3f vector3f2, float _float) {
        vector3f0.set(
            vector3f1.x + (vector3f2.x - vector3f1.x) * _float,
            vector3f1.y + (vector3f2.y - vector3f1.y) * _float,
            vector3f1.z + (vector3f2.z - vector3f1.z) * _float
        );
        return vector3f0;
    }

    public static Vector2 lerp(Vector2 out, Vector2 a, Vector2 b, float t) {
        out.set(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t);
        return out;
    }

    public static float c_lerp(float src, float dest, float alpha) {
        float _float = (float)(1.0 - Math.cos((double)(alpha * (float) Math.PI))) / 2.0F;
        return src * (1.0F - _float) + dest * _float;
    }

    public static Quaternion slerp(Quaternion quaternion2, Quaternion quaternion1, Quaternion quaternion0, float _float) {
        double double0 = (double)(quaternion1.x * quaternion0.x + quaternion1.y * quaternion0.y + quaternion1.z * quaternion0.z + quaternion1.w * quaternion0.w);
        double double1 = double0 < 0.0 ? -double0 : double0;
        double double2 = (double)(1.0F - _float);
        double double3 = (double)_float;
        if (1.0 - double1 > 0.1) {
            double double4 = org.joml.Math.acos(double1);
            double double5 = org.joml.Math.sin(double4);
            double double6 = 1.0 / double5;
            double2 = org.joml.Math.sin(double4 * (1.0 - (double)_float)) * double6;
            double3 = org.joml.Math.sin(double4 * (double)_float) * double6;
        }

        if (double0 < 0.0) {
            double3 = -double3;
        }

        quaternion2.set(
            (float)(double2 * (double)quaternion1.x + double3 * (double)quaternion0.x),
            (float)(double2 * (double)quaternion1.y + double3 * (double)quaternion0.y),
            (float)(double2 * (double)quaternion1.z + double3 * (double)quaternion0.z),
            (float)(double2 * (double)quaternion1.w + double3 * (double)quaternion0.w)
        );
        return quaternion2;
    }

    public static float sqrt(float val) {
        return org.joml.Math.sqrt(val);
    }

    public static float lerpFunc_EaseOutQuad(float x) {
        return x * x;
    }

    public static float lerpFunc_EaseInQuad(float x) {
        float _float = 1.0F - x;
        return 1.0F - _float * _float;
    }

    public static float lerpFunc_EaseOutInQuad(float x) {
        return x < 0.5F ? lerpFunc_EaseOutQuad(x) * 2.0F : 0.5F + lerpFunc_EaseInQuad(2.0F * x - 1.0F) / 2.0F;
    }

    public static double tryParseDouble(String varStr, double defaultVal) {
        if (StringUtils.isNullOrWhitespace(varStr)) {
            return defaultVal;
        } else {
            try {
                return Double.parseDouble(varStr.trim());
            } catch (NumberFormatException numberFormatException) {
                return defaultVal;
            }
        }
    }

    public static float tryParseFloat(String varStr, float defaultVal) {
        if (StringUtils.isNullOrWhitespace(varStr)) {
            return defaultVal;
        } else {
            try {
                return Float.parseFloat(varStr.trim());
            } catch (NumberFormatException numberFormatException) {
                return defaultVal;
            }
        }
    }

    public static boolean canParseFloat(String varStr) {
        if (StringUtils.isNullOrWhitespace(varStr)) {
            return false;
        } else {
            try {
                Float.parseFloat(varStr.trim());
                return true;
            } catch (NumberFormatException numberFormatException) {
                return false;
            }
        }
    }

    public static int tryParseInt(String varStr, int defaultVal) {
        if (StringUtils.isNullOrWhitespace(varStr)) {
            return defaultVal;
        } else {
            try {
                return Integer.parseInt(varStr.trim());
            } catch (NumberFormatException numberFormatException) {
                return defaultVal;
            }
        }
    }

    public static float degToRad(float degrees) {
        return (float) (Math.PI / 180.0) * degrees;
    }

    public static float radToDeg(float radians) {
        return (180.0F / (float)Math.PI) * radians;
    }

    public static float getClosestAngle(float in_radsA, float in_radsB) {
        float float0 = wrap(in_radsA, (float) (Math.PI * 2));
        float float1 = wrap(in_radsB, (float) (Math.PI * 2));
        float float2 = float1 - float0;
        return wrap(float2, (float) -Math.PI, (float) Math.PI);
    }

    public static float getClosestAngleDegrees(float in_degsA, float in_degsB) {
        float float0 = degToRad(in_degsA);
        float float1 = degToRad(in_degsB);
        float float2 = getClosestAngle(float0, float1);
        return radToDeg(float2);
    }

    public static int sign(float val) {
        return val > 0.0F ? 1 : (val < 0.0F ? -1 : 0);
    }

    public static int fastfloor(double x) {
        int _int = (int)x;
        return x < (double)_int ? _int - 1 : _int;
    }

    public static int fastfloor(float x) {
        int _int = (int)x;
        return x < (float)_int ? _int - 1 : _int;
    }

    public static float floor(float val) {
        return (float)fastfloor(val);
    }

    public static float ceil(float val) {
        return val >= 0.0F ? (float)((int)(val + 0.9999999F)) : (float)((int)(val - 1.0E-7F));
    }

    public static float frac(float val) {
        float _float = floor(val);
        return val - _float;
    }

    public static float wrap(float val, float range) {
        if (range == 0.0F) {
            return 0.0F;
        } else if (range < 0.0F) {
            return 0.0F;
        } else if (val < 0.0F) {
            float float0 = -val / range;
            float float1 = 1.0F - frac(float0);
            return float1 * range;
        } else {
            float float2 = val / range;
            float float3 = frac(float2);
            return float3 * range;
        }
    }

    public static float wrap(float in_val, float in_min, float in_max) {
        float float0 = max(in_max, in_min);
        float float1 = min(in_max, in_min);
        float float2 = float0 - float1;
        float float3 = in_val - float1;
        float float4 = wrap(float3, float2);
        return float1 + float4;
    }

    public static float max(float a, float b) {
        return a > b ? a : b;
    }

    public static int max(int a, int b) {
        return a > b ? a : b;
    }

    public static float min(float a, float b) {
        return a > b ? b : a;
    }

    public static int min(int a, int b) {
        return a > b ? b : a;
    }

    public static float abs(float val) {
        return val * (float)sign(val);
    }

    public static boolean equal(float a, float b) {
        return equal(a, b, 1.0E-7F);
    }

    public static boolean equal(float a, float b, float delta) {
        float float0 = b - a;
        float float1 = abs(float0);
        return float1 < delta;
    }

    public static Matrix4f convertMatrix(org.joml.Matrix4f matrix4f1, Matrix4f matrix4f0) {
        if (matrix4f0 == null) {
            matrix4f0 = new Matrix4f();
        }

        matrix4f0.m00 = matrix4f1.m00();
        matrix4f0.m01 = matrix4f1.m01();
        matrix4f0.m02 = matrix4f1.m02();
        matrix4f0.m03 = matrix4f1.m03();
        matrix4f0.m10 = matrix4f1.m10();
        matrix4f0.m11 = matrix4f1.m11();
        matrix4f0.m12 = matrix4f1.m12();
        matrix4f0.m13 = matrix4f1.m13();
        matrix4f0.m20 = matrix4f1.m20();
        matrix4f0.m21 = matrix4f1.m21();
        matrix4f0.m22 = matrix4f1.m22();
        matrix4f0.m23 = matrix4f1.m23();
        matrix4f0.m30 = matrix4f1.m30();
        matrix4f0.m31 = matrix4f1.m31();
        matrix4f0.m32 = matrix4f1.m32();
        matrix4f0.m33 = matrix4f1.m33();
        return matrix4f0;
    }

    public static org.joml.Matrix4f convertMatrix(Matrix4f matrix4f1, org.joml.Matrix4f matrix4f0) {
        if (matrix4f0 == null) {
            matrix4f0 = new org.joml.Matrix4f();
        }

        return matrix4f0.set(
            matrix4f1.m00,
            matrix4f1.m01,
            matrix4f1.m02,
            matrix4f1.m03,
            matrix4f1.m10,
            matrix4f1.m11,
            matrix4f1.m12,
            matrix4f1.m13,
            matrix4f1.m20,
            matrix4f1.m21,
            matrix4f1.m22,
            matrix4f1.m23,
            matrix4f1.m30,
            matrix4f1.m31,
            matrix4f1.m32,
            matrix4f1.m33
        );
    }

    public static float step(float from, float to, float delta) {
        if (from > to) {
            return max(from + delta, to);
        } else {
            return from < to ? min(from + delta, to) : from;
        }
    }

    public static PZMath.SideOfLine testSideOfLine(float x1, float y1, float x2, float y2, float px, float py) {
        float _float = (px - x1) * (y2 - y1) - (py - y1) * (x2 - x1);
        return _float > 0.0F ? PZMath.SideOfLine.Left : (_float < 0.0F ? PZMath.SideOfLine.Right : PZMath.SideOfLine.OnLine);
    }

    public static float roundToNearest(float val) {
        int _int = sign(val);
        return floor(val + 0.5F * (float)_int);
    }

    public static int roundToInt(float val) {
        return (int)(roundToNearest(val) + 1.0E-4F);
    }

    public static float roundToIntPlus05(float val) {
        return floor(val) + 0.5F;
    }

    public static float roundFromEdges(float val) {
        float float0 = (float)((int)val);
        float float1 = val - float0;
        if (float1 < 0.2F) {
            return float0 + 0.2F;
        } else {
            return float1 > 0.8F ? float0 + 1.0F - 0.2F : val;
        }
    }

    static {
        PZMath.UnitTests.runAll();
    }

    public static enum SideOfLine {
        Left,
        OnLine,
        Right;
    }

    private static final class UnitTests {
        private static final Runnable[] s_unitTests = new Runnable[0];

        private static void runAll() {
            PZArrayUtil.forEach(s_unitTests, Runnable::run);
        }

        private static final class getClosestAngle {
            public static void run() {
                DebugLog.General.println("runUnitTests_getClosestAngle");
                DebugLog.General.println("a, b, result, expected, pass");
                runUnitTest(0.0F, 0.0F, 0.0F);
                runUnitTest(0.0F, 15.0F, 15.0F);
                runUnitTest(15.0F, 0.0F, -15.0F);
                runUnitTest(0.0F, 179.0F, 179.0F);
                runUnitTest(180.0F, 180.0F, 0.0F);
                runUnitTest(180.0F, 359.0F, 179.0F);
                runUnitTest(90.0F, 180.0F, 90.0F);
                runUnitTest(180.0F, 90.0F, -90.0F);

                for (short short0 = -360; short0 < 360; short0 += 10) {
                    for (short short1 = -360; short1 < 360; short1 += 10) {
                        float float0 = (float)short0;
                        float float1 = (float)short1;
                        runUnitTest_noexp(float0, float1);
                    }
                }

                DebugLog.General.println("runUnitTests_getClosestAngle. Complete");
            }

            private static void runUnitTest_noexp(float float1, float float2) {
                float float0 = PZMath.getClosestAngleDegrees(float1, float2);
                logResult(float1, float2, float0, "N/A", "N/A");
            }

            private static void runUnitTest(float float1, float float2, float float3) {
                float float0 = PZMath.getClosestAngleDegrees(float1, float2);
                boolean _boolean = PZMath.equal(float3, float0, 1.0E-4F);
                String string = _boolean ? "pass" : "fail";
                logResult(float1, float2, float0, String.valueOf(float3), string);
            }

            private static void logResult(float float2, float float1, float float0, String string0, String string1) {
                DebugLog.General.println("%f, %f, %f, %s, %s", float2, float1, float0, string0, string1);
            }
        }

        private static final class lerpFunctions {
            public static void run() {
                DebugLog.General.println("UnitTest_lerpFunctions");
                DebugLog.General.println("x,Sqrt,EaseOutQuad,EaseInQuad,EaseOutInQuad");

                for (int _int = 0; _int < 100; _int++) {
                    float _float = (float)_int / 100.0F;
                    DebugLog.General
                        .println(
                            "%f,%f,%f,%f",
                            _float,
                            PZMath.lerpFunc_EaseOutQuad(_float),
                            PZMath.lerpFunc_EaseInQuad(_float),
                            PZMath.lerpFunc_EaseOutInQuad(_float)
                        );
                }

                DebugLog.General.println("UnitTest_lerpFunctions. Complete");
            }
        }

        public static final class vector2 {
            public static void run() {
                runUnitTest_direction();
            }

            private static void runUnitTest_direction() {
                DebugLog.General.println("runUnitTest_direction");
                DebugLog.General.println("x, y, angle, length, rdir.x, rdir.y, rangle, rlength, pass");
                checkDirection(1.0F, 0.0F);
                checkDirection(1.0F, 1.0F);
                checkDirection(0.0F, 1.0F);
                checkDirection(-1.0F, 1.0F);
                checkDirection(-1.0F, 0.0F);
                checkDirection(-1.0F, -1.0F);
                checkDirection(0.0F, -1.0F);
                checkDirection(1.0F, -1.0F);
                DebugLog.General.println("runUnitTest_direction. Complete");
            }

            private static void checkDirection(float float0, float float1) {
                Vector2 vector20 = new Vector2(float0, float1);
                float float2 = vector20.getDirection();
                float float3 = vector20.getLength();
                Vector2 vector21 = Vector2.fromLengthDirection(float3, float2);
                float float4 = vector21.getDirection();
                float float5 = vector21.getLength();
                boolean _boolean = PZMath.equal(vector20.x, vector21.x, 1.0E-4F)
                    && PZMath.equal(vector20.y, vector21.y, 1.0E-4F)
                    && PZMath.equal(float2, float4, 1.0E-4F)
                    && PZMath.equal(float3, float5, 1.0E-4F);
                DebugLog.General
                    .println(
                        "%f, %f, %f, %f, %f, %f, %f, %f, %s",
                        float0,
                        float1,
                        float2,
                        float3,
                        vector21.x,
                        vector21.y,
                        float4,
                        float5,
                        _boolean ? "true" : "false"
                    );
            }
        }
    }
}
